package rtk;

import android.annotation.TargetApi;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.os.Build;

import java.util.List;
import java.util.Timer;
import java.util.TimerTask;


/**
 * Created by apple on 2017/5/29.
 */

@TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR2)
public class BleManager {

    private BluetoothGatt mBluetoothGatt = null;
    private GattCallback mGattCallback;
    private int mStatus = BluetoothGatt.STATE_DISCONNECTED;

    private Timer mTimeoutTimer;
    private Timer mRssiTimer;

    private BluetoothDevice mDevice;

    public BleManager() {
    }

    protected void connect(BluetoothDevice device, GattCallback callback) {
        connect(device, 8000, false, callback);
    }

    protected void connect(BluetoothDevice device, long timeOut, boolean autoConnect, GattCallback callback) {
        if (device == null)
            return;
        disconnect();
        mBluetoothGatt = device.connectGatt(RtkManager.getContext(), autoConnect, mBluetoothGattCallback);
        mGattCallback = callback;
        mTimeoutTimer = new Timer();
        mTimeoutTimer.schedule(new TimerTask() {
            public void run() {
                if (mStatus != BluetoothGatt.STATE_CONNECTED) {
                    if (mGattCallback != null)
                        mGattCallback.onTimeOut();
                    disconnect();
                }
                if (mTimeoutTimer != null)
                    mTimeoutTimer.cancel();
            }
        }, timeOut);
    }

    public void disconnect() {
        mGattCallback = null;
        if (mBluetoothGatt != null) {
            mBluetoothGatt.disconnect();
            mBluetoothGatt.close();
        }
        if (mTimeoutTimer != null)
            mTimeoutTimer.cancel();
        if (mRssiTimer != null)
            mRssiTimer.cancel();
        mDevice = null;
    }

    public synchronized int write(byte[] buffer) {
        if (buffer != null && this.mBluetoothGatt != null && mDevice != null) {
            BluetoothGattService rxService = mBluetoothGatt.getService(BleUUID.RX_SERVICE_UUID);
            if (rxService != null) {
                BluetoothGattCharacteristic rxChar = rxService.getCharacteristic(BleUUID.RX_CHAR_UUID);
                if (rxChar != null) {
                    rxChar.setValue(buffer);
                    try {
                        Thread.sleep(10L);
                    } catch (InterruptedException var5) {

                    }
                    if (mBluetoothGatt.writeCharacteristic(rxChar)) {
                        return 0;
                    }
                }
            }
        }
        return 1;
    }


    private final BluetoothGattCallback mBluetoothGattCallback = new BluetoothGattCallback() {

        private final String BUFFER_ON_READ = "BUFFER_ON_READ";

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            mStatus = newState;
            if (newState == BluetoothGatt.STATE_CONNECTING) {

            } else if (newState == BluetoothGatt.STATE_CONNECTED) {
                mDevice = gatt.getDevice();
                if (!gatt.discoverServices()) {
                    startWork(gatt);
                }
            } else if (newState == BluetoothGatt.STATE_DISCONNECTED || newState == BluetoothGatt.STATE_DISCONNECTING) {
                mDevice = null;
                if (mGattCallback != null)
                    mGattCallback.onDisconnected();
            } else {
                mDevice = null;
                if (mGattCallback != null)
                    mGattCallback.onConnectionError();
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                List services = gatt.getServices();
                startWork(gatt);
            } else {
                mDevice = null;
                if (mGattCallback != null)
                    mGattCallback.onConnectionError();
            }

        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            byte[] readBuffer = characteristic.getValue();
            synchronized (BUFFER_ON_READ) {
                if (mGattCallback != null)
                    mGattCallback.onRead(readBuffer);
            }
        }

        @Override
        public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
            if (status == 0 && mGattCallback != null) {
                mGattCallback.onRSSI(rssi, status);
            }
        }

        @Override
        public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if (mGattCallback != null)
                if (status == BluetoothGatt.GATT_SUCCESS) {
                    mGattCallback.onWrite(true);
                } else {
                    mGattCallback.onWrite(false);
                }
        }


        public void startWork(BluetoothGatt gatt) {

            if (mBluetoothGatt != null) {
                BluetoothGattService bluetoothGattService = mBluetoothGatt.getService(BleUUID.RX_SERVICE_UUID);
                BluetoothGattCharacteristic txCharUuid = bluetoothGattService.getCharacteristic(BleUUID.TX_CHAR_UUID);
                mBluetoothGatt.setCharacteristicNotification(txCharUuid, true);
                BluetoothGattDescriptor descriptor = txCharUuid.getDescriptor(BleUUID.CLIENT_CHARACTERISTIC_CONFIG_DESCRIPTOR_UUID);
                descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                mBluetoothGatt.writeDescriptor(descriptor);
            }

            if (mGattCallback != null)
                mGattCallback.onConnected(gatt.getDevice());

            if (mRssiTimer != null)
                mRssiTimer.cancel();
            mRssiTimer = new Timer();
            mRssiTimer.schedule(new TimerTask() {
                public void run() {
                    if (mBluetoothGatt != null) {
                        mBluetoothGatt.readRemoteRssi();
                    }
                }
            }, 0L, 1000L);

        }
    };


    public boolean isConnected() {
        return mDevice != null && mStatus == BluetoothGatt.STATE_CONNECTED;
    }

    public int getConnectStatus() {
        return mStatus;
    }
}
